home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
hity wydania
/
Ubuntu 9.10 PL
/
karmelkowy-koliberek-desktop-9.10-i386-PL.iso
/
casper
/
filesystem.squashfs
/
usr
/
bin
/
gnome-about
< prev
next >
Wrap
Text File
|
2009-11-03
|
37KB
|
1,046 lines
#!/usr/bin/python
# coding=utf-8
'''
gnome-about
# Pretty About Dialog for the GNOME Desktop #
Copyright (C) 2007 Guillaume Seguin <guillaume@segu.in>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Authors:
Guillaume Seguin <guillaume@segu.in>
Vincent Untz <vuntz@gnome.org> (get_language_names () helper function)
'''
import pygtk
pygtk.require ('2.0')
import gobject
from gobject.option import OptionParser, make_option
import gtk
import cairo
from math import pi
import os, sys, random, time, gettext, locale
import xml.dom.minidom
DESCRIPTION_DELAY = 10000
CONTRIBUTOR_DELAY = 2500
PACKAGE = "gnome-desktop"
VERSION = "2.28.1"
GETTEXT_PACKAGE = "gnome-desktop-2.0"
LOCALEDIR = "/usr/share/locale"
DATADIR = "/usr/share/gnome-about"
ICONDIR = "/usr/share/pixmaps"
LOGO_FILE = "gnome-64.png"
gettext.install (GETTEXT_PACKAGE, LOCALEDIR, unicode = True)
header_links = [
(_("About GNOME"), "http://www.gnome.org/about/"),
(_("News"), "http://news.gnome.org/"),
(_("GNOME Library"), "http://library.gnome.org/"),
(_("Friends of GNOME"), "http://www.gnome.org/friends/"),
(_("Contact"), "http://www.gnome.org/contact/"),
]
translated_contributors = [
_("The Mysterious GEGL"),
_("The Squeaky Rubber GNOME"),
_("Wanda The GNOME Fish")
]
default_link_color = gtk.gdk.Color (0, 0, 65535)
def locate_file (file):
'''Wrap gnome_program_locate_file to avoid ugly duplication'''
dirnames = [DATADIR, '.']
for dirname in dirnames:
filename = os.path.join(dirname, file)
if os.path.exists(filename):
return filename
return False
def cleanup_date (date):
'''Parse a date as found in gnome-version.xml and nicely format it'''
try:
# FIXME: we don't have g_locale_to_utf8 in python. See bug #530382
return unicode (time.strftime ("%x", time.strptime (date, "%Y-%m-%d")), locale.getpreferredencoding ()).encode ("utf-8")
except:
return ""
# Imported from GNOME's Sabayon
# (sabayon/admin-tool/lockdown/disabledapplets.py)
# There's no wrapper for g_get_language_names (). Ugly workaround:
# Note that we don't handle locale alias...
def get_language_names ():
if "LANGUAGE" in os.environ.keys () and os.environ["LANGUAGE"] != "":
env_lang = os.environ["LANGUAGE"].split ()
elif "LC_ALL" in os.environ.keys () and os.environ["LC_ALL"] != "":
env_lang = os.environ["LC_ALL"].split ()
elif "LC_MESSAGES" in os.environ.keys () and os.environ["LC_MESSAGES"] != "":
env_lang = os.environ["LC_MESSAGES"].split ()
elif "LANG" in os.environ.keys () and os.environ["LANG"] != "":
env_lang = os.environ["LANG"].split ()
else:
env_lang = []
env_lang.reverse ()
languages = []
for language in env_lang:
start_pos = 0
mask = 0
uscore_pos = language.find ("_")
if uscore_pos != -1:
start_pos = uscore_pos
mask += 1 << 2
dot_pos = language.find (".", start_pos)
if dot_pos != -1:
start_pos = dot_pos
mask += 1 << 0
at_pos = language.find ("@", start_pos)
if at_pos != -1:
start_pos = at_pos
mask += 1 << 1
if uscore_pos != -1:
lang = language[:uscore_pos]
elif dot_pos != -1:
lang = language[:dot_pos]
elif at_pos != -1:
lang = language[:at_pos]
else:
lang = language
if uscore_pos != -1:
if dot_pos != -1:
territory = language[uscore_pos:dot_pos]
elif at_pos != -1:
territory = language[uscore_pos:at_pos]
else:
territory = language[uscore_pos:]
else:
territory = ""
if dot_pos != -1:
if at_pos != -1:
codeset = language[dot_pos:at_pos]
else:
codeset = language[dot_pos:]
else:
codeset = ""
if at_pos != -1:
modifier = language[at_pos:]
else:
modifier = ""
for i in range (mask + 1):
if i & ~mask == 0:
newlang = lang
if (i & 1 << 2):
newlang += territory
if (i & 1 << 0):
newlang += codeset
if (i & 1 << 1):
newlang += modifier
languages.insert (0, newlang)
return languages
class GettableList (list):
'''Dumb wrapper around Python list with a get () method to iterate \
the list'''
current = 0
def get (self):
if not len (self):
return None
if self.current == -1:
item = None
else:
item = self[self.current]
self.current += 1
if self.current == len (self):
self.current = -1
else:
self.current = self.current % len (self)
return item
class GnomeContributors (GettableList):
'''Randomized contributors list'''
current = 0
def __init__ (self):
'''Initiate object and load contributors lists'''
super (GnomeContributors, self).__init__ ()
map (self.append, translated_contributors)
self.load_from_file ("contributors.list")
self.load_from_file ("foundation-members.list")
random.shuffle (self) # Randomize list...
def load_from_file (self, file):
'''Load a list of contributors and validate it'''
def validate_contributor (contrib):
try:
contrib.encode ("utf8")
return len (contrib) > 0 and contrib[0] != "#"
except Exception, e:
print e
return False
path = locate_file (file)
if not path:
print '''Warning: "%s" file not found.''' % file
return
f = open (path, "r")
try:
data = f.readlines ()
finally:
f.close ()
'''Cleanup list'''
data = map (lambda s: s.rstrip (), data)
'''Check that the file begins with the correct header'''
if not data or data[0] != "# gnome-about contributors - format 1":
return
'''Filter the contributors list and append it'''
contributors = filter (validate_contributor, data)
map (self.append, contributors)
def get (self):
'''Return a contributor from the currently randomized list. \
If we hit the end of the list, randomize it again'''
contributors_count = len (self)
if not contributors_count:
print "Warning: empty contributors list."
return
contributor = self[self.current]
self.current += 1
if self.current >= contributors_count:
'''Remove the last item of the list and reinsert it after \
shuffling to make sure it won't get displayed twice in a row'''
self.pop ()
random.shuffle (self)
index = random.randint (contributors_count / 2,
contributors_count)
self.insert (index, contributor)
self.current = 0
return contributor
# Animation is done using:
# * A custom gtk.Label, for catching mouse press events
# * A gtk.Alignment, for positionning and scrolling (the actual animation)
# * A gtk.Layout, so that the Alignment can be wider than what's displayed
# and thus let the Label appear and disappear smoothly
class AnimatedLabel (gtk.Layout):
'''Pretty animated label'''
items = None # items must either be a GettableList object
# or expose a get () method'''
timeout = 0
format = "" # format must be a valid formatting string for a single %s
item = None
next = None
current = None
label = None
source = None
state = 0 # 0 = appearing ; 1 = landed ; 2 = vanishing
pos = 0.0
width = 0
height = 0
def __init__ (self, items, width, height, timeout, format = "%s"):
'''Initiate object'''
super (AnimatedLabel, self).__init__ ()
self.items = items
self.next = self.items.get () # Pop the first item
self.width = width
self.height = height
self.timeout = timeout
self.format = format
self.set_size_request (width, height)
self.connect ("button-press-event", self.on_button_press)
self.connect ("map", self.reset_animation)
def reset_animation (self, *args):
'''Reset label and fire animation timer'''
self.reset_label ()
if not self.label:
return
self.source = gobject.timeout_add (5, self.animate)
def make_label (self):
'''Build the label widgets'''
self.label = WindowedLabel ()
self.label.connect ("button-press-event", self.on_button_press)
self.label.set_justify (gtk.JUSTIFY_FILL)
self.label.set_line_wrap (True)
self.label.set_markup (self.format % self.item)
self.label.set_selectable (True)
def reset_label (self):
'''Drop current label if any and create the new one'''
if self.current:
self.remove (self.current)
self.current = None
self.label = None
self.item = self.next
self.next = self.items.get ()
if not self.item:
return False
self.make_label ()
self.state = -1
def on_button_press (self, widget, event):
'''Switch to next item upon left click'''
if event.button != 1 or not self.current:
return
# Remove the current timeout if any to avoid bad side effects
if self.source:
gobject.source_remove (self.source)
self.animate ()
return True
class VertAnimatedLabel (AnimatedLabel):
'''Vertically animated label'''
rewind_text = ""
last_label_height = 0
def rewind_animate (self):
'''Animation function for the rewind step'''
self.source = None
if self.state == -2:
self.item = self.rewind_text
self.make_label ()
label_height = self.label.size_request ()[1]
total_height = self.height + label_height
self.pos = float (self.last_label_height) / total_height
self.current.set (0.5, self.pos, 0, 0)
self.state = 0
self.source = gobject.timeout_add (10, self.rewind_animate)
elif self.state == 0:
if self.pos < 1.0:
'''Move towards the bottom position'''
self.pos = min (1.0, self.pos + 0.01)
self.current.set (0.5, self.pos, 0, 0)
self.source = gobject.timeout_add (10, self.rewind_animate)
else:
'''Bottommost position reached'''
self.rewind_text = ""
self.reset_animation ()
return False
def animate (self):
'''The actual animation function'''
self.source = None
if self.state == -2:
self.rewind_animate ()
elif self.state == -1:
self.rewind_text += "\n\n%s" % self.item
self.state = 0
self.animate ()
elif self.state == 0:
if self.pos:
'''Move towards the top position'''
self.pos = max (0, self.pos - 0.02)
label_height = self.label.size_request ()[1]
total_height = self.height + label_height
real_pos = float (self.pos * self.height + label_height) \
/ total_height
self.current.set (0.5, real_pos, 0, 0)
self.source = gobject.timeout_add (5, self.animate)
else:
'''Topmost position reached'''
self.state = 1
self.pos = 1.0
self.source = gobject.timeout_add (self.timeout, self.animate)
elif self.state == 1:
'''Dont let selected labels vanish until they are unselected'''
if self.label.get_selection_bounds () == ():
self.state = 2
self.source = gobject.timeout_add (5, self.animate)
elif self.state == 2:
if not self.next:
self.state = -2
self.last_label_height = self.label.size_request ()[1]
self.reset_animation ()
self.source = gobject.timeout_add (1, self.animate)
elif self.pos:
'''Move out of the visible region of the Layout'''
self.pos = max (0, self.pos - 0.02)
label_height = self.label.size_request ()[1]
total_height = self.height + label_height
real_pos = float (self.pos * label_height) \
/ total_height
self.current.set (0.5, real_pos, 0, 0)
self.source = gobject.timeout_add (5, self.animate)
else:
'''Label has disappeared, bye bye'''
self.reset_animation ()
return False
def make_label (self):
'''Build a new label widget'''
super (VertAnimatedLabel, self).make_label ()
if not self.label:
return
self.label.set_size_request (self.width, -1)
self.current = gtk.Alignment (0.0, 1.0)
label_height = self.label.size_request ()[1]
height = self.size_request ()[1]
self.current.set_size_request (-1, 2 * label_height + height)
self.current.add (self.label)
self.put (self.current, 0, - label_height)
self.pos = 1.0
self.show_all ()
class HorzAnimatedLabel (AnimatedLabel):
'''Horizontally animated label'''
def animate (self):
'''The actual animation function'''
self.source = None
if self.state == -2:
self.reset_animation ()
elif self.state <= 0:
if self.pos != 0.5:
'''Move towards the center position'''
self.pos = max (0.5, self.pos - 0.02)
self.current.set (self.pos, 0.5, 0, 0)
self.source = gobject.timeout_add (5, self.animate)
else:
'''Center position reached, switch to return mode'''
self.state = 1
self.source = gobject.timeout_add (self.timeout, self.animate)
elif self.state == 1:
'''Dont let selected labels vanish until they are unselected'''
if self.label.get_selection_bounds () == ():
self.state = 2
self.source = gobject.timeout_add (5, self.animate)
elif self.state == 2:
if self.pos:
'''Disappear by moving left'''
self.pos = max (0, self.pos - 0.02)
self.current.set (self.pos, 0.5, 0, 0)
self.source = gobject.timeout_add (5, self.animate)
else:
'''Left position reached, let's move on'''
self.reset_animation ()
return False
def make_label (self):
'''Build a new label widget'''
super (HorzAnimatedLabel, self).make_label ()
if not self.label:
return
self.label.set_size_request (-1, self.height)
self.current = gtk.Alignment (1.0, 0.0)
label_width = self.label.size_request ()[0]
width = self.size_request ()[0]
self.current.set_size_request (2 * label_width + width, -1)
self.current.add (self.label)
self.put (self.current, - label_width, 0)
self.pos = 1.0
self.show_all ()
class WindowedLabel (gtk.Label):
'''Custom gtk.Label with an overlapping input-only gtk.gdk.Window'''
event_window = None
def __init__ (self, debug = False):
'''Initialize object and plug all signals'''
self.debug = debug
super (WindowedLabel, self).__init__ ()
def do_realize (self):
'''Create a custom GDK window with which we will be able to play'''
gtk.Label.do_realize (self)
event_mask = self.get_events () | gtk.gdk.BUTTON_PRESS_MASK \
| gtk.gdk.BUTTON_RELEASE_MASK \
| gtk.gdk.KEY_PRESS_MASK
self.event_window = gtk.gdk.Window (parent = self.get_parent_window (),
window_type = gtk.gdk.WINDOW_CHILD,
wclass = gtk.gdk.INPUT_ONLY,
event_mask = event_mask,
x = self.allocation.x,
y = self.allocation.y,
width = self.allocation.width,
height = self.allocation.height)
self.event_window.set_user_data (self)
def do_unrealize (self):
'''Destroy event window on unrealize'''
self.event_window.set_user_data (None)
self.event_window.destroy ()
gtk.Label.do_unrealize (self)
def do_size_allocate (self, allocation):
'''Move & resize the event window to fit the Label's one'''
gtk.Label.do_size_allocate (self, allocation)
if self.flags () & gtk.REALIZED:
self.event_window.move_resize (allocation.x, allocation.y,
allocation.width, allocation.height)
def do_map (self):
'''Show event window'''
gtk.Label.do_map (self)
self.event_window.show ()
'''Raise the event window to make sure it is over the Label's one'''
self.event_window.raise_ ()
def do_unmap (self):
'''Hide event window on unmap'''
self.event_window.hide ()
gtk.Label.do_unmap (self)
gobject.type_register (WindowedLabel)
class HyperLink (WindowedLabel):
'''Clickable www link label'''
url = ""
menu = None
selection = None
def __init__ (self, label, url):
'''Initialize object'''
super (HyperLink, self).__init__ ()
markup = "<b><u>%s</u></b>" % label
self.set_markup (markup)
self.set_selectable (True)
self.url = url
self.create_menu ()
link_color = self.style_get_property ("link-color")
if not link_color:
link_color = default_link_color
self.modify_fg (gtk.STATE_NORMAL, link_color)
def open_url (self, *args):
'''Use GNOME API to open the url'''
try:
gtk.show_uri (self.get_screen(), self.url, 0)
except Exception, e:
print '''Warning: could not open "%s": %s''' % (self.url, e)
def copy_url (self, *args):
'''Copy URL to Clipboard'''
clipboard = gtk.clipboard_get ("CLIPBOARD")
clipboard.set_text (self.url)
def create_menu (self):
'''Create the popup menu that will be displayed upon right click'''
self.menu = gtk.Menu ()
open_item = gtk.ImageMenuItem (_("_Open URL"))
open_image = gtk.image_new_from_stock (gtk.STOCK_OPEN,
gtk.ICON_SIZE_MENU)
open_item.set_image (open_image)
open_item.connect ("activate", self.open_url)
open_item.show ()
self.menu.append (open_item)
copy_item = gtk.ImageMenuItem (_("_Copy URL"))
copy_image = gtk.image_new_from_stock (gtk.STOCK_COPY,
gtk.ICON_SIZE_MENU)
copy_item.set_image (copy_image)
copy_item.connect ("activate", self.copy_url)
copy_item.show ()
self.menu.append (copy_item)
def display_menu (self, button, time, place = False):
'''Display utility popup menu'''
if place:
alloc = self.get_allocation ()
pos = self.event_window.get_origin ()
x = pos[0]
y = pos[1] + alloc.height
func = lambda *a: (x, y, True)
else:
func = None
self.menu.popup (None, None, func, button, time)
def do_map (self):
'''Select the HAND2 cursor on map'''
WindowedLabel.do_map (self)
cursor = gtk.gdk.Cursor (gtk.gdk.HAND2)
self.event_window.set_cursor (cursor)
def do_button_press_event (self, event):
'''Update selection bounds infos or display popup menu'''
if event.button == 1:
self.selection = self.get_selection_bounds ()
elif event.button == 3:
self.display_menu (event.button, event.time)
return True
WindowedLabel.do_button_press_event (self, event)
def do_button_release_event (self, event):
'''Open url if selection hasn't changed since initial press'''
if event.button == 1:
selection = self.get_selection_bounds ()
if selection == self.selection:
self.open_url ()
return True
WindowedLabel.do_button_release_event (self, event)
def do_key_press_event (self, event):
'''Open url when Return key is pressed'''
if event.keyval == gtk.keysyms.Return:
self.open_url ()
return True
elif event.keyval == gtk.keysyms.Menu \
or (event.keyval == gtk.keysyms.F10 \
and event.state & gtk.accelerator_get_default_mod_mask() == \
gtk.gdk.SHIFT_MASK):
self.display_menu (event.keyval, event.time, place = True)
return True
WindowedLabel.do_key_press_event (self, event)
gobject.type_register (HyperLink)
class GnomeLogo (gtk.Widget):
'''Simple widget displaying a colored GNOME logo'''
_surface = None
_parent = None
_file = None
def __init__ (self, parent, file):
'''Initialize object and do the initial painting'''
gtk.Widget.__init__ (self)
self._parent = parent
self._file = file
self.paint_surface ()
width = self._surface.get_width ()
height = self._surface.get_height ()
self.set_size_request (width, height)
self.set_flags(self.flags() | gtk.NO_WINDOW)
def paint_surface (self):
'''Paint image and color overlay'''
self._surface = cairo.ImageSurface.create_from_png (self._file)
text_color = self._parent.get_style ().fg[gtk.STATE_NORMAL]
cr = cairo.Context (self._surface)
cr.set_source_rgb (float (text_color.red) / 65535,
float (text_color.green) / 65535,
float (text_color.blue) / 65535)
cr.set_operator (cairo.OPERATOR_ATOP)
cr.paint ()
def do_expose_event (self, event):
'''Paint the saved surface to the widget context'''
cr = self.window.cairo_create ()
cr.set_operator (cairo.OPERATOR_OVER)
cr.set_source_surface (self._surface, 10, 10)
cr.paint ()
def do_style_set (self, *args):
'''Style changed, let's repaint image'''
self.paint_surface ()
self.queue_draw ()
gobject.type_register (GnomeLogo)
class GnomeAboutHeader (gtk.Layout):
'''Pretty header for gnome-about'''
links = []
width = 0
height = 0
def __init__ (self, links):
'''Initialize object, plug map signal'''
super (GnomeAboutHeader, self).__init__ ()
self.links = links
def do_realize (self):
'''Load header and build links'''
gtk.Layout.do_realize (self)
current_x = 0
current_y = 0
base_y = 0
header = self.load_header ()
if header:
self.put (header, 0, 0)
current_y = header.get_pixbuf ().get_height ()
base_y = current_y + 4
line = self.create_line ()
image = gtk.Image ()
image.set_from_pixmap (line, None)
self.put (image, 0, current_y)
logo = self.load_logo ()
if logo:
self.put (logo, 0, 0)
logo_size = logo.get_size_request ()
current_x += logo_size[0] + 25
current_y = logo_size[1] + 20
dot = self.create_dot ()
def make_link_widget (link):
'''Helper function which makes an HyperLink and shows it'''
label = HyperLink (link[0], link[1])
label.show_all ()
return label
widgets = map (make_link_widget, self.links)
put_widgets = 0
for widget in widgets:
if put_widgets > 0:
if dot:
image = gtk.Image ()
image.set_from_pixmap (dot, None)
self.put (image, current_x + 5, base_y + 6)
current_x += 16
self.put (widget, current_x, base_y)
current_x += widget.size_request ()[0]
put_widgets += 1
self.width = current_x + 10
self.height = current_y
self.set_size_request (self.width, self.height)
self.show_all ()
def load_header (self):
'''Load a random header image as a gtk.Image'''
directory = locate_file ("headers")
if not directory:
print "Warning: header images directory not found."
return None
try:
headers = os.listdir (directory)
except:
print "Warning: failed to read header images directory."
return None
headers = filter (lambda s: s[-4:] in (".png", ".gif"), headers)
header = random.choice (headers)
file = os.path.join (directory, header)
try:
pixbuf = gtk.gdk.pixbuf_new_from_file (file)
except:
print '''Warning: failed to load header image "%s".''' % file
return None
image = gtk.Image ()
image.set_from_pixbuf (pixbuf)
return image
def load_logo (self):
'''Load a GNOME foot logo as a gtk.Image'''
file = locate_file (LOGO_FILE)
if not file:
print '''Warning: GNOME logo file "%s" not found.''' % LOGO_FILE
return None
try:
logo = GnomeLogo (self, file)
except Exception:
print '''Warning: failed to load GNOME logo image "%s".''' % file
return None
return logo
def create_dot (self):
'''Create a pixmap containing a simple dot'''
pixmap = gtk.gdk.Pixmap (self.window, 6, 6)
context = pixmap.cairo_create ()
context.set_operator (cairo.OPERATOR_SOURCE)
context.set_source_color (self.style.bg[self.state])
context.paint ()
context.set_operator (cairo.OPERATOR_OVER)
context.set_source_color (self.style.fg[self.state])
context.arc (3, 3, 2.3, 0, 2 * pi)
context.fill ()
return pixmap
def create_line (self, width = 2000, height = 1):
'''Create a pixmap containing a simple line'''
pixmap = gtk.gdk.Pixmap (self.window, width, height)
context = pixmap.cairo_create ()
context.set_operator (cairo.OPERATOR_SOURCE)
context.set_source_rgb (0, 0, 0)
context.paint ()
return pixmap
gobject.type_register (GnomeAboutHeader)
class GnomeAbout (gtk.Dialog):
'''Super pretty About Dialog for the GNOME Desktop'''
header = None
contributors = None
description_messages = GettableList ()
system_infos = []
def __init__ (self, ui = True):
'''Initialize underlying gnome.Program, Contributors list, UI...'''
super (GnomeAbout, self).__init__ (_("About the GNOME Desktop"),
buttons = (gtk.STOCK_CLOSE,
gtk.RESPONSE_CLOSE))
# Immediately fetch system infos to load description messages
self.system_infos = self.get_system_infos ()
if not ui:
return
self.contributors = GnomeContributors ()
icon_file = ICONDIR + "/gnome-logo-icon-transparent.png"
try:
self.set_icon_from_file (icon_file)
except gobject.GError:
pass
self.create_ui ()
self.set_default_response (gtk.RESPONSE_CLOSE)
self.set_position (gtk.WIN_POS_CENTER)
map (lambda prop: self.set_property (prop[0], prop[1]),
[("allow-grow", False), ("allow-shrink", False)])
self.connect ("delete-event", gtk.main_quit)
self.connect ("response", self.response_callback)
def gnome_version (self):
'''Output basic GNOME version information to console'''
def print_info (info):
infos_dict = {"name": info[0], "value": info[1]}
# Translators: %(name)s and %(value)s should not be translated:
# it's a way to identify a string, so just handle them like %s
print _("%(name)s: %(value)s") % infos_dict
map (print_info, self.system_infos)
def create_ui (self):
'''Fill our Dialog with some lovely widgets'''
self.set_has_separator (False)
main_box = self.get_children ()[0] # Get the internal Dialog VBox
'''Pretty header'''
self.header = GnomeAboutHeader (header_links)
main_box.pack_start (self.header)
welcome_label = WindowedLabel ()
welcome_label.set_markup ("<big><big><b>%s</b></big></big>" % \
_("Welcome to the GNOME Desktop"))
main_box.pack_start (welcome_label)
descriptions_label = VertAnimatedLabel (self.description_messages,
300, 120,
DESCRIPTION_DELAY, "%s")
welcome_label.connect ("button-press-event",
descriptions_label.on_button_press)
box = gtk.EventBox ()
alignment = gtk.Alignment (0.5, 0.5)
alignment.set_padding (10, 10, 0, 0)
alignment.add (descriptions_label)
box.connect ("button-press-event", descriptions_label.on_button_press)
box.add (alignment)
main_box.pack_start (box)
by_label = WindowedLabel (True)
by_label.set_markup ("<big><b>%s</b></big>" % _("Brought to you by:"))
main_box.pack_start (by_label)
alignment = gtk.Alignment (0.5, 0.5)
'''Realize the header right now to get everything (especially the
contributors list) correctly positionned and sized.'''
self.header.realize ()
width = self.header.width
label = HorzAnimatedLabel (self.contributors, width,
30, CONTRIBUTOR_DELAY, "<b>%s</b>")
by_label.connect ("button-press-event", label.on_button_press)
label.show_all ()
alignment.add (label)
main_box.pack_start (alignment)
'''System info labels'''
def make_info_label (info):
if not info[1]:
return False
label = gtk.Label ()
infos_dict = {"name": info[0], "value": info[1]}
# Translators: %(name)s and %(value)s should not be translated:
# it's a way to identify a string, so just handle them like %s
label.set_markup (_("<b>%(name)s:</b> %(value)s") % infos_dict)
label.set_selectable (True)
label.connect ("focus-out-event",
lambda l, e: l.select_region (-1, -1))
alignment = gtk.Alignment (0, 0.5)
alignment.set_padding (0, 4, 8, 0)
alignment.add (label)
return alignment
info_labels = map (make_info_label, self.system_infos)
info_labels = filter (lambda l: l <> False, info_labels)
map (lambda l: main_box.pack_start (l, False, False), info_labels)
main_box.show_all ()
def get_system_infos (self):
'''Fetch various system infos'''
file = locate_file ("gnome-version.xml")
if not file:
print '''Warning: "gnome-version.xml" file not found.'''
return []
f = open (file, "r")
try:
document = xml.dom.minidom.parse (f)
finally:
f.close ()
if document.firstChild.nodeName != "gnome-version":
print '''Warning: corrupted "gnome-version.xml".'''
return []
infos = {
"platform" : "",
"minor" : "",
"micro" : "",
"distributor" : "",
"date" : ""
}
for node in document.firstChild.childNodes:
if node.nodeName in infos:
infos[node.nodeName] = node.firstChild.nodeValue
elif node.nodeName == "description":
self.load_description_messages (node)
'''Format version'''
if not len (infos["platform"]):
version = ""
elif not len (infos["minor"]):
version = infos["platform"]
elif not len (infos["micro"]):
version = "%s.%s" % (infos["platform"], infos["minor"])
else:
version = "%s.%s.%s" % (infos["platform"], infos["minor"],
infos["micro"])
date = cleanup_date (infos["date"])
retval = []
if version:
retval.append((_("Version"), version))
if infos["distributor"]:
retval.append((_("Distributor"), infos["distributor"]))
if date:
retval.append((_("Build Date"), date))
return retval
def load_description_messages (self, node):
'''Find the best translation of each description message'''
languages = get_language_names () + [""]
def desc_filter_func (node):
'''Helper filter function for XML descriptions'''
return node.nodeName == "p" \
and node.getAttribute ("xml:lang") in languages
def desc_sort_func (a, b):
'''Helper sorting function to sort translated messages'''
return cmp (languages.index (a), languages.index (b))
descs = filter (desc_filter_func, node.childNodes)
raw_descs = filter (lambda n: n.getAttribute ("xml:lang") == "", descs)
i = -1
translations = []
for desc in raw_descs:
new_i = descs.index (desc)
if i != - 1:
# Append the previous description
translations.append (descs[i:new_i])
i = new_i
# Open ended to retrieve all translation for last description
translations.append (descs[i:])
messages = GettableList ()
for block in translations:
sorted_descs = sorted (block, cmp = desc_sort_func,
key = lambda n: n.getAttribute ("xml:lang"))
best = sorted_descs[0].firstChild.nodeValue
messages.append (best)
self.description_messages = messages
def response_callback (self, widget, response):
'''Handle dialog response when Close button is triggered'''
if response == gtk.RESPONSE_CLOSE:
gtk.main_quit ()
if __name__ == "__main__":
parser = OptionParser (
option_list = [
make_option ("--gnome-version",
action="store_true",
dest="gnome_version",
help=_("Display information on this GNOME version")),
# FIXME: remove this when we can get all the default
# options
make_option ("--version",
action="store_true",
dest="version",
help=VERSION),
])
#FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=496278
parser.parse_args (sys.argv)
if parser.values.gnome_version:
about = GnomeAbout (ui = False)
about.gnome_version ()
elif parser.values.version:
print "GNOME gnome-about %s" % (VERSION)
else:
about = GnomeAbout ()
about.show_all ()
try:
gtk.main ()
except KeyboardInterrupt:
pass